#include "backtest/questdb_backtest.h"
#include <spdlog/spdlog.h>
#include <questdb/ilp/line_tcp.h>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <algorithm>

namespace hft {

QuestDBBacktest::QuestDBBacktest(const BacktestConfig& config)
    : BacktestSystem(config), current_capital_(config.initial_capital) {
}

bool QuestDBBacktest::initialize() {
    spdlog::info("Initializing QuestDB backtest system");
    return true;
}

bool QuestDBBacktest::loadData() {
    spdlog::info("Loading historical data from QuestDB");
    return loadDataFromQuestDB();
}

bool QuestDBBacktest::loadDataFromQuestDB() {
    try {
        // 创建QuestDB客户�?
        auto client = questdb_ilp_line_tcp_create();
        if (!client) {
            spdlog::error("Failed to create QuestDB client");
            return false;
        }

        // 连接QuestDB
        if (!questdb_ilp_line_tcp_connect(client, "127.0.0.1", 9000)) {
            spdlog::error("Failed to connect to QuestDB");
            questdb_ilp_line_tcp_destroy(client);
            return false;
        }

        // 构建查询
        std::stringstream query;
        query << "SELECT * FROM market_data WHERE timestamp BETWEEN '"
              << config_.start_date << "' AND '" << config_.end_date << "'"
              << " AND symbol IN ('" << config_.symbols[0] << "'";
        for (size_t i = 1; i < config_.symbols.size(); ++i) {
            query << ",'" << config_.symbols[i] << "'";
        }
        query << ") ORDER BY timestamp";

        spdlog::info("Executing query: {}", query.str());

        // 执行查询
        auto result = questdb_ilp_line_tcp_query(client, query.str().c_str());
        if (!result) {
            spdlog::error("Failed to execute query");
            questdb_ilp_line_tcp_destroy(client);
            return false;
        }

        // 处理结果
        int count = 0;
        while (questdb_ilp_line_tcp_next(result)) {
            MarketDataMessage data;
            data.symbol = questdb_ilp_line_tcp_get_string(result, "symbol");
            data.timestamp = std::chrono::system_clock::from_time_t(
                questdb_ilp_line_tcp_get_timestamp(result, "timestamp"));
            data.last_price = questdb_ilp_line_tcp_get_double(result, "last_price");
            data.volume = questdb_ilp_line_tcp_get_int64(result, "volume");
            data.turnover = questdb_ilp_line_tcp_get_double(result, "turnover");
            data.open_interest = questdb_ilp_line_tcp_get_int64(result, "open_interest");
            data.bid_price = questdb_ilp_line_tcp_get_double(result, "bid_price");
            data.bid_volume = questdb_ilp_line_tcp_get_int64(result, "bid_volume");
            data.ask_price = questdb_ilp_line_tcp_get_double(result, "ask_price");
            data.ask_volume = questdb_ilp_line_tcp_get_int64(result, "ask_volume");

            data_cache_[data.symbol].push_back(data);
            count++;
        }

        spdlog::info("Loaded {} market data records", count);

        // 清理资源
        questdb_ilp_line_tcp_destroy(result);
        questdb_ilp_line_tcp_destroy(client);

        if (count == 0) {
            spdlog::error("No data found for the specified time range and symbols");
            return false;
        }

        spdlog::info("Successfully loaded historical data");
        return true;

    } catch (const std::exception& e) {
        spdlog::error("Error loading data: {}", e.what());
        return false;
    }
}

BacktestResult QuestDBBacktest::run(std::shared_ptr<Strategy> strategy) {
    spdlog::info("Starting backtest");

    // 初始化策�?
    if (!strategy->initialize()) {
        spdlog::error("Failed to initialize strategy");
        return result_;
    }

    // 设置策略回调
    strategy->setOrderCallback([this](const Order& order) {
        executeOrder(order);
    });

    // 运行回测
    strategy->start();
    processMarketData();
    strategy->stop();

    // 计算指标
    calculateMetrics();

    spdlog::info("Backtest completed");
    return result_;
}

void QuestDBBacktest::processMarketData() {
    // 按时间顺序处理所有数�?
    while (true) {
        MarketDataMessage* next_data = nullptr;
        std::string next_symbol;

        // 找到最早的数据
        for (const auto& [symbol, data_queue] : data_cache_) {
            if (!data_queue.empty()) {
                if (!next_data || data_queue.front().timestamp < next_data->timestamp) {
                    next_data = &data_queue.front();
                    next_symbol = symbol;
                }
            }
        }

        if (!next_data) break;

        // 更新当前时间
        current_time_ = next_data->timestamp;

        // 更新市场数据
        updateMarketData(*next_data);

        // 移除已处理的数据
        data_cache_[next_symbol].pop_front();
    }
}

void QuestDBBacktest::updateMarketData(const MarketDataMessage& data) {
    // 更新最新价�?
    last_prices_[data.symbol] = data.last_price;

    // 更新持仓市�?
    if (positions_.find(data.symbol) != positions_.end()) {
        double position_value = positions_[data.symbol] * data.last_price;
        current_capital_ += position_value;
    }

    // 记录权益曲线
    equity_curve_.emplace_back(current_time_, current_capital_);
}

void QuestDBBacktest::executeOrder(const Order& order) {
    // 计算成交价格（考虑滑点�?
    double execution_price = order.price;
    if (order.side == OrderSide::BUY) {
        execution_price *= (1.0 + config_.slippage);
    } else {
        execution_price *= (1.0 - config_.slippage);
    }

    // 计算手续�?
    double commission = order.price * order.volume * config_.commission_rate;

    // 创建成交记录
    Trade trade;
    trade.order_id = order.order_id;
    trade.symbol = order.symbol;
    trade.price = execution_price;
    trade.volume = order.volume;
    trade.side = order.side;
    trade.timestamp = current_time_;

    // 记录交易
    recordTrade(trade);

    // 更新持仓
    updatePositions();
}

void QuestDBBacktest::updatePositions() {
    for (const auto& trade : trades_) {
        positions_[trade.symbol] += (trade.side == OrderSide::BUY ? 1 : -1) * trade.volume;
    }
}

void QuestDBBacktest::recordTrade(const Trade& trade) {
    trades_.push_back(trade);
}

void QuestDBBacktest::calculateMetrics() {
    calculateReturns();
    calculateDrawdown();
    calculateSharpeRatio();
    calculateWinRate();
    calculateProfitFactor();
    calculateAverageTrade();
    calculateAverageHoldingTime();
}

void QuestDBBacktest::calculateReturns() {
    result_.returns.clear();
    for (size_t i = 1; i < equity_curve_.size(); ++i) {
        double daily_return = (equity_curve_[i].second - equity_curve_[i-1].second) 
                            / equity_curve_[i-1].second;
        result_.returns.push_back(daily_return);
    }
    result_.total_return = (equity_curve_.back().second - config_.initial_capital) 
                         / config_.initial_capital;
}

void QuestDBBacktest::calculateDrawdown() {
    result_.drawdown.clear();
    double peak = config_.initial_capital;
    double max_drawdown = 0.0;

    for (const auto& [time, equity] : equity_curve_) {
        if (equity > peak) {
            peak = equity;
        }
        double drawdown = (peak - equity) / peak;
        result_.drawdown.push_back(drawdown);
        max_drawdown = std::max(max_drawdown, drawdown);
    }

    result_.max_drawdown = max_drawdown;
}

void QuestDBBacktest::calculateSharpeRatio() {
    if (result_.returns.empty()) {
        result_.sharpe_ratio = 0.0;
        return;
    }

    double mean_return = 0.0;
    for (double ret : result_.returns) {
        mean_return += ret;
    }
    mean_return /= result_.returns.size();

    double variance = 0.0;
    for (double ret : result_.returns) {
        variance += (ret - mean_return) * (ret - mean_return);
    }
    variance /= result_.returns.size();

    double std_dev = std::sqrt(variance);
    result_.sharpe_ratio = mean_return / std_dev * std::sqrt(252); // 年化
}

void QuestDBBacktest::calculateWinRate() {
    result_.total_trades = trades_.size();
    result_.winning_trades = 0;
    result_.losing_trades = 0;

    for (const auto& trade : trades_) {
        double pnl = (trade.side == OrderSide::BUY ? 1 : -1) * trade.volume * trade.price;
        if (pnl > 0) {
            result_.winning_trades++;
        } else if (pnl < 0) {
            result_.losing_trades++;
        }
    }

    result_.win_rate = static_cast<double>(result_.winning_trades) / result_.total_trades;
}

void QuestDBBacktest::calculateProfitFactor() {
    double total_profit = 0.0;
    double total_loss = 0.0;

    for (const auto& trade : trades_) {
        double pnl = (trade.side == OrderSide::BUY ? 1 : -1) * trade.volume * trade.price;
        if (pnl > 0) {
            total_profit += pnl;
        } else {
            total_loss += std::abs(pnl);
        }
    }

    result_.profit_factor = total_loss > 0 ? total_profit / total_loss : 0.0;
}

void QuestDBBacktest::calculateAverageTrade() {
    double total_pnl = 0.0;
    for (const auto& trade : trades_) {
        total_pnl += (trade.side == OrderSide::BUY ? 1 : -1) * trade.volume * trade.price;
    }
    result_.avg_trade = result_.total_trades > 0 ? total_pnl / result_.total_trades : 0.0;
}

void QuestDBBacktest::calculateAverageHoldingTime() {
    if (trades_.empty()) {
        result_.avg_holding_time = 0.0;
        return;
    }

    double total_holding_time = 0.0;
    for (size_t i = 1; i < trades_.size(); i += 2) {
        if (i < trades_.size()) {
            auto holding_time = std::chrono::duration_cast<std::chrono::seconds>(
                trades_[i].timestamp - trades_[i-1].timestamp).count();
            total_holding_time += holding_time;
        }
    }

    result_.avg_holding_time = total_holding_time / (trades_.size() / 2);
}

} // namespace hft 